package com.ikingtech.framework.sdk.authenticate.embedded.authenticate;

import com.ikingtech.framework.sdk.authenticate.embedded.core.Credential;
import com.ikingtech.framework.sdk.authenticate.embedded.core.UserIdentityLoader;
import com.ikingtech.framework.sdk.authenticate.extension.IdentityExtensionLoader;
import com.ikingtech.framework.sdk.context.security.Identity;
import com.ikingtech.framework.sdk.context.security.Me;
import com.ikingtech.framework.sdk.context.exception.FrameworkException;
import com.ikingtech.framework.sdk.enums.authenticate.SignEndpointTypeEnum;
import com.ikingtech.framework.sdk.utils.Tools;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.List;

/**
 * @author tie yan
 */
public class PasswordAuthenticate extends AbstractAuthenticate {

	private final UserIdentityLoader userIdentityLoader;

	private final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

	public PasswordAuthenticate(StringRedisTemplate redisTemplate, List<IdentityExtensionLoader> loaders, UserIdentityLoader userIdentityLoader) {
		super(redisTemplate, loaders);
		this.userIdentityLoader = userIdentityLoader;
	}

	@Override
	public Identity doVerify(Credential credential, String token) {
		Identity result = this.userIdentityLoader.loadByCredential(credential.getCredentialName());

		if (result == null) {
			throw new FrameworkException("userNotFound");
		}

		if (Boolean.TRUE.equals(result.getLocked())) {
			throw new FrameworkException("userLocked");
		}

		if (!this.passwordEncoder.matches(credential.getPassword(), result.getPassword())) {
			throw new FrameworkException("invalidUsernameOrPassword");
		}

		this.resolveMultiSign(result.getId(), Me.tenantCode());
		result.setEndpoint(SignEndpointTypeEnum.PC.name());
		result.setToken(token);

		return result;
	}

	@Override
	public Boolean support(Credential credential) {
		return Tools.Str.isNotBlank(credential.getCredentialName()) && Tools.Str.isNotBlank(credential.getPassword());
	}
}
